﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.Linq;

namespace CarbonExchange.Bll.AmeeAnswers
{

    /// <summary>
    /// Summary description for BaseProfileItem
    /// </summary>
    public abstract class AmeeProfileItem
    {
        public enum ProfileResourceTypes
        {
            ProfileCategoryResource,
            ProfileItemResource
        }

        protected AmeeProfileItem()
        {
        }

        protected AmeeProfileItem(XElement item, string path)
        {
            ProfileResourceTypes type = (ProfileResourceTypes)Enum.Parse(typeof(ProfileResourceTypes), item.Document.Root.Elements().Single().Name.LocalName);

            this.Id = item.Attribute("uid").Value;

            switch (type)
            {
                case ProfileResourceTypes.ProfileCategoryResource:
                    this.Name = item.Element("name").Value;
                    this.AmountPerMonth = float.Parse(item.Element("amountPerMonth").Value);
                    this.DataItemUid = item.Element("dataItemUid").Value;
                    this.Path = string.Concat(item.Document.Root.Elements().Single().Element("Path").Value, "/", item.Element("path").Value);
                    List<CustomItem> tmp = new List<CustomItem>();
                    InitCustomProperties(tmp);
                    _CustomProperties = tmp.AsQueryable();
                    foreach (CustomItem tmpProp in _CustomProperties)
                    {
                        if (item.Element(tmpProp.Path) != null)
                        {
                            tmpProp.SetValue(item.Element(tmpProp.Path).Value);
                        }
                    }
                    break;
                case ProfileResourceTypes.ProfileItemResource:
                    this.Name = item.Element("Name").Value;
                    this.AmountPerMonth = float.Parse(item.Element("AmountPerMonth").Value);
                    this.DataItemUid = item.Element("DataItem").Attribute("uid").Value;
                    this.Path = item.Parent.Element("Path").Value;
                    _CustomProperties = (from elem in item.Element("ItemValues").Elements("ItemValue") select new CustomItem(elem.Element("ItemValueDefinition").Element("ValueDefinition").Element("ValueType").Value, elem.Element("Name").Value, elem.Element("Value").Value, elem.Element("Path").Value)).AsQueryable();
                    break;
            }
        }

        protected virtual void InitCustomProperties(List<CustomItem> properties)
        {
        }

        public string Id { get; private set; }
        public string Name { get; set; }
        public float AmountPerMonth { get; set; }
        public string DataItemUid { get; set; }

        private IQueryable<CustomItem> _CustomProperties { get; set; }
        public CustomItem[] CustomProperties { get { return _CustomProperties != null ? _CustomProperties.ToArray() : null; } }

        public string Path { get; private set; }

        protected void SetCustomPropValue(string path, object value)
        {
            _CustomProperties.Where(p => p.Path == path).Single().SetValue(value);
        }

        protected object GetCustomPropValue(string path)
        {
            return _CustomProperties.Where(p => p.Path == path).Single().Value;
        }
        


    }

    public class CustomItem
    {

        internal CustomItem(Types type, string name, string path)
        {
            this.Name = name;
            this.Path = path;
            this.DataType = type;
        }

        /*internal CustomItem(Types type, string name, string value, string path)
        {
            this.Name = name;
            this.Path = path;
            this.DataType = type;
            SetValue(value);
        }*/

        internal CustomItem(string path, object value)
        {
            this.Path = path;
            if (value is string)
            {
                this.DataType = Types.String;
                this.Value = value;
            }
            else if (value is decimal)
            {
                this.DataType = Types.Decimal;
                this.Value = value;
            }
            else if (value is int)
            {
                this.DataType = Types.Integer;
                this.Value = value;
            }
            else if(value != null)
            {
                throw new NotImplementedException(string.Format("Data Type '{0}' specified for '{1}' not implimented. Please do so.", value.GetType().ToString(), path));
            }
            else if (value == null)
            {
                throw new NotImplementedException(string.Format("Data Type specified for '{0}' not implimented and value is null. Please do so.", path));
            }
        }

        internal CustomItem(string type, string name, string value, string path)
        {
            this.Name = name;
            this.Path = path;
            if (type.ToUpper() == "STRING" || type.ToUpper() == "TEXT")
            {
                DataType = Types.String;
                SetValue(value);
            }
            else if (type.ToUpper() == "INTEGER")
            {
                DataType = Types.Integer;
                SetValue(value);
            }
            else if (type.ToUpper() == "DECIMAL")
            {
                DataType = Types.Decimal;
                SetValue(value);
            }
            else
            {
                throw new NotImplementedException(string.Format("Data Type '{0}' not implimented. Please do so.", type));
            }
        }

        public enum Types
        {
            Null,
            String,
            Integer,
            Decimal
        }

        internal void SetValue(object value)
        {
            Value = value;
        }

        internal void SetValue(string value)
        {
            switch (DataType)
            {
                case Types.String:
                    this.Value = value;
                    break;
                case Types.Integer:
                    this.Value = string.IsNullOrEmpty(value) ? 0 : int.Parse(value);
                    break;
                case Types.Decimal:
                    this.Value = string.IsNullOrEmpty(value) ? 0m : decimal.Parse(value);
                    break;
                default:
                    throw new NotImplementedException(string.Format("Data Type '{0}' not implimented. Please do so.", DataType.ToString()));
            }
        }



        public Types DataType { get; private set; }
        public string Name { get; internal set; }
        public object Value { get; private set; }
        public string Path { get; private set; }

        public T GetValue<T>()
        {
            return (T)this.Value;
        }

        internal string GetAmeeValue()
        {
            switch (DataType)
            {
                case Types.String:
                    return (string)Value;
                case Types.Integer:
                    return ((int)Value).ToString();
                case Types.Decimal:
                    return ((decimal)Value).ToString();
                default:
                    throw new NotImplementedException(string.Format("Data Type '{0}' not implimented. Please do so.", DataType.ToString()));
            }
        }
 
    }
}